﻿

using System.Collections;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System;
using ZDK.Infra.Services;

namespace ZDK.Utilities
{
    public class TcpClient
    {
        readonly IMyLog _log;

        #region SocketAndBuffer
        private class SocketAndBuffer
        {
            public Socket Socket;

            public byte[] Buffer;

            public SocketAndBuffer()
            {
                Buffer = new byte[8193];
            }
        }
        #endregion

        //private static ArrayList __ENCList = new ArrayList();
        private Socket _serverSocket;
        private Socket _myClientSocket;
        private TcpServer _myParentObj;
        private byte[] oldbytes;
        private string _ipAddress;
        private int _port;
        private IPEndPoint _clientEP;
        private ManualResetEvent _allDone;

        public TcpClient(IMyLog log, Socket serverSocket, Socket clientSocket, TcpServer parentObj)
        {
            _log = log;
            //__ENCList.Add(new WeakReference(this));
            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _myClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _allDone = new ManualResetEvent(initialState: false);
            _serverSocket = serverSocket;
            _myClientSocket = clientSocket;
            _myParentObj = parentObj;
            _clientEP = (IPEndPoint)_myClientSocket.RemoteEndPoint;
            _ipAddress = _clientEP.Address.ToString();
            _port = _clientEP.Port;
        }

        public void ClientThreadProc()
        {
            try
            {
                SocketAndBuffer socketAndBuffer = new SocketAndBuffer();
                socketAndBuffer.Socket = _myClientSocket;
                socketAndBuffer.Socket.BeginReceive(socketAndBuffer.Buffer, 0, socketAndBuffer.Buffer.Length, SocketFlags.None, ReceiveCallBack, socketAndBuffer);
                _allDone.WaitOne();
            }
            catch (Exception ex)
            {
                _log.Error($"ClientThreadProc 异常：{ex.Message}");
            }
        }

        private void ReceiveCallBack(IAsyncResult ar)
        {
            string key = _ipAddress + ":" + _port;
            bool syncFlag = true;
            if (_myParentObj._socketSyncStatusDict.TryGetValue(key, out syncFlag))
            {
                if (syncFlag == false)
                {
                    _log.Warn($"ReceiveCallBack退出：syncFlag = false");
                    return;
                }
            }

            _allDone.Set();
            SocketAndBuffer socketAndBuffer = (SocketAndBuffer)ar.AsyncState;
            try
            {
                if (!socketAndBuffer.Socket.Connected)
                {
                    return;
                }
                int len = socketAndBuffer.Socket.EndReceive(ar);
                if (len > 0)
                {
                    oldbytes = new byte[len];
                    Array.Copy(socketAndBuffer.Buffer, 0, oldbytes, 0, len);
                    _myParentObj.OnReceive(key, oldbytes);
                    socketAndBuffer.Socket.BeginReceive(socketAndBuffer.Buffer, 0, socketAndBuffer.Buffer.Length, SocketFlags.None, ReceiveCallBack, socketAndBuffer);
                }
                else if (_myClientSocket != null)
                {
                    _myClientSocket.Close();
                    _myClientSocket = null;
                    if (_clientEP != null)
                    {
                        TcpServer._clients.Remove(key);
                        _myParentObj.OnServerDown(key);
                        _myParentObj.GetClientClose(_ipAddress, _port);
                    }
                }
            }
            catch (Exception ex)
            {
                _log.Error($"[ReceiveCallBack]异常：{ex.Message}");
                if (_myClientSocket != null)
                {
                    _myClientSocket.Close();
                    _myClientSocket = null;
                    if (_ipAddress != null)
                    {
                        TcpServer._clients.Remove(key);
                        _myParentObj.OnServerDown(key);
                        _myParentObj.GetClientClose(_ipAddress, _port);
                    }
                }
            }
        }
    }
}
